<?php
/**
 * Wikipedia page representation classes
 *
 * Classes relating to representing a Wikipedia page 
 * as a PHP object
 *
 * @author Rob Young
 * @package forage.examples.wikipedia
 */

/**
 * Basic class for representing a Wikipedia document
 */
class WikipediaPage 
{
  /**
   * Page details
   */
  private $id, $title, $text;
  
  /**
   * Magic setter
   * Set values on DTO properties
   *
   * @param string $name
   * @param string $value
   */
  public function __set($name, $value)
  {
    switch ($name) {
    case 'id':
    case 'title':
    case 'text':
      $this->$name = $value;
    }
  }

  /**
   * Magic getter
   * Provide access to DTO properries
   *
   * @param string $name
   * @return string
   */
  public function __get($name)
  {
    switch ($name) {
    case 'id':
    case 'title':
    case 'text':
      return $this->$name;
    case 'text_stripped':
      return $this->strip($this->text);
    case 'categories':
      return $this->extractCategories($this->text);
    case 'is_redirect':
      return $this->isRedirect();
    }
  }

  /**
   * Test if page is a redirect
   *
   * @return boolean
   */
  public function isRedirect()
  {
    return substr($this->text, 0, 9) == '#REDIRECT';
  }

  /**
   * Return text stripped of wikitext
   *
   * @param strin $text
   * @return string
   */
  public function strip($text)
  {
    require_once 'Text/Wiki.php';
    
    // prevent it from echoing with some output buffering
    ob_start();
    $text = Text_Wiki::singleton('Mediawiki')->transform($text, 'plain');
    ob_get_clean();

    // remove <ref> and </ref> tags
    $text = preg_replace('#</?ref>#i', '', $text);

    // remove dodgy terms with ampersands in
    $text = preg_replace('#\w+&\w+#', '', $text);

    // process standard templates
    $text = preg_replace_callback('#\{\{(\w+)\s+(.*)\|(.*)\}\}#Us', array($this, 'stripTemplateCallback'), $text);
    
    return $text;
  }

  public function extractCategories($text)
  {
    $categories = array();
    if (preg_match_all('#\[\[Category:(.*)\]\]#U', $text, $matches)) {
      foreach ($matches[1] as $category) {
        $categories[] = $category;
      }
    }
    return $categories;
  }

  /**
   * Callback to strip templates from text
   *
   * @param array $matches
   * @return string
   */
  private function stripTemplateCallback($matches)
  {
    $type = strtolower(trim($matches[2]));
    switch (strtolower($matches[1])) {
    case 'cite': return $this->stripCitation($type, $matches[3]);
    default: return '';
    }
  }

  /**
   * Strip out citations from the text
   *
   * @param string $type
   * @param string $data
   * @return string
   */
  private function stripCitation($type, $data)
  {
    $type    = strtolower(trim($type));
    $details = $this->extractBracedHash($data);

    switch ($type) {
    case 'web':
      $use = array('title', 'last', 'first', 'author');
      break;
    case 'book':
      $use = array('title', 'last', 'first');
      break;
    default:
      return '';
    }

    $out = '';
    foreach ($use as $key) {
      if (isset($details[$key])) {
        $out .= ' ' . $details[$key];
      }
    }
    return trim($out);
  }

  /**
   * Extract clauses
   * 
   * @param string $text
   * @return string
   */
  private function extractBracedHash($text)
  {
    $hash = array();
    $clauses = explode('|', $text);
    foreach ($clauses as $clause) {
      if ($clause && strpos($clause, '=')!==false) {
        list($key, $value) = explode('=', $clause, 2);
        $hash[str_replace("\n", "", trim($key))] = str_replace("\n", "", trim($value));
      }
    }

    return $hash;
  }

  /**
   * String representation of this object
   *
   * @return string
   */
  public function __toString()
  {
    return $this->title . ' [' . $this->id . ']';
  }
}

